﻿// ## 2020/08/09 # 氕氘氚 # 更新menu的id为unit_menu::菜单_部队 ##
// ## 2022/08/26 # 黑店小小二 # 修复解散部队兵力6万时数据溢出导致无法解散bug ##
// ## 2022/02/14 # 江东新风 # 部分常量中文化 ##
// ## 2022/02/13 # 江东新风 # 换帅限战斗部队 ##
// ## 2022/01/25 # 江东新风 # 运输队强行军物资损耗，部队强行军入城无代价修复 ##
// ## 2022/01/08 # 江东新风 # 恢复->招募乡勇 ##
// ## 2021/10/24 # 江东新风 # 将pk::add_troops换成ch::add_troops以修正显示错误 ##
// ## 2020/10/30 # 江东新风 # 同步马术书大神的更新 ##  	
// ## 2020/09/30 # 江东新风 # 移动过后无法执行换帅 ##
// ## 2020/09/21 # 江东新风 # ch::add_tp替换 ##
// ## 2020/08/16 # 江东新风#has_skill函数替換##
// ## 2020/08/09 # 氕氘氚 # 优化回归规则 ##
// ## 2020/08/08 # 氕氘氚 # 修复了換帅取消时可以再次行动的bug ##
/*
@ 만든이: 기마책사
@ UPDATE: '18.11.4   /  최초적용: 계략_공작/도발/고무/대고무/회귀, 부대해산/병합
@ UPDATE: '18.11.8   /  변경내용: 계략_욕설 추가, 계략启用 특기조건 반영
@ UPDATE: '18.11.14  /  변경내용: 게략_기습 추가, 강행군추가
@ UPDATE: '18.11.24  /  변경내용: 계략_도발 통합(욕설삭제)+설전추가, 계략_기습 수상 추가, 부대해산/병합 실행가능 병력기준 변경, NPC부대 지력차계산 추가
@ UPDATE: '18.11.25  /  변경내용: 스크립트 구조변경, 부대설전 버그개선을 위하여 trigger 방식채용
@ UPDATE: '18.11.30  /  변경내용: 계략_기습 버그방지조건 추가, 部队指挥_解散 기준값 오류수정
@ UPDATE: '18.12.3   /  변경내용: 계략_기습 빈칸없는 목표부대 검색 오류수정, 계략_도발 발동오류 개선 및 불러오기 실행 시 초기화 추가
@ UPDATE: '18.12.12  /  변경내용: 계략_기습 기력소모 수정, shift+우클릭 메뉴 무한행동 启用시 오류 수정, 部队指挥_解散/병합 주변적군 확인조건 추가
@ UPDATE: '18.12.21  /  변경내용: 部队指挥_合并 설명수정, 계략_낙석 추가
@ UPDATE: '18.12.23  /  변경내용: 部队指挥_解散/병합 주위의적 검색함수 오류 수정
@ UPDATE: '18.12.30  /  변경내용: 계략_도발 特技_论客 우대 적용, 部队指挥_换帅 추가 (주장변경기능), 계략_공작 적시설 탈취 기능 추가


@ 수정자: HoneyBee
@ 내용: 부대묘책메뉴 SCRIPT 추가에 따른 기력 밸런스 재조정 (계략에 소모되는 기력 수치 재조정)

*/

namespace 야전부대메뉴
{

    //---------------------------------------------------------------------------------------
    // 유저 설정 (true = on, false = off)

    // 부대 메뉴 추가여부 설정
    const bool 部队指挥_解散_启用 = true;    // 2천명 이상 부대 강제 해산 ('18.11.9)
    const bool 部队指挥_合并_启用 = true;    // 동일 병과부대 인접 시 병력 인계 ('18.11.6)
    const bool 部队指挥_招募乡勇_启用 = true;    // 금을 소비하여 병력 회복 ('18.11.6)
    const bool 部队指挥_换帅_启用 = true;    // 부대의 주장 변경 ('18.12.26)
    const bool 部队指挥_强行军_启用 = true;   // 기력 추가 소비하여 추가 이동 실시 ('18.11.13)

    // 계략에 대한 특기 옵션
    const bool 계략_특기_설정 = true;        // 계략에 대한 특기 설정 启用
    const bool 백출_반감_설정 = true;        // true= 50% 소비, false = 무조건 1 소비
    const bool 계략_병력_차등 = true;        // 병력수에 따른 계략 소비기력 차등 적용

    // 강행군 실행 조건
    const int ENERGY_MIN_강행군 = 10;       // 강행군을 실행하기 위한 최소 기력
    const float MOVEMENT_强行军 = 0.6f;    // [강행군_이동력]/[부대_이동력] 비율 


    // 부대 실행 조건
    const int GOLD_COST_병합 = 500;   // 아직 启用안하는 조건    
    const int GOLD_COST_招募乡勇 = 300;

    //---------------------------------------------------------------------------------------


    class Main
    {
        Main()
        {
            // 부대 메뉴 추가
            add_menu_unit_order();
            pk::bind(111, pk::trigger111_t(onForceBegin));

        }

        pk::unit@ src_unit;
        pk::unit@ dst_unit;
        pk::point src_pos_;
        pk::point dst_pos_;

        pk::unit@ src_unit_debate;
        pk::unit@ dst_unit_debate;

        pk::list<pk::unit@> unit_debate_list;
        int debate_result;

        void onForceBegin(pk::force@ force)
        {
            if (!pk::is_alive(force) or force.get_id() >= 非贼势力_末) return ;
            pk::list<pk::unit@> unit_list = pk::get_unit_list(force);
            if (unit_list.count > 0)
            {
                for (int i = 0; i < (unit_list.count); i += 1)
                {
                    pk::unit@ unit = unit_list[i];
                    if (pk::is_player_controlled(unit)) continue;
                    
                    if (unit.troops <= 50 and unit.gold >= GOLD_COST_招募乡勇 and check_spec_around(unit))
                    {
                        pk::person@ person = pk::get_person(src_unit.leader);
                        if (person.rank >= 官职_无 and person.mibun == 身份_一般) continue;
                        @src_unit = @unit;
                        handler_部队指挥_招募乡勇(unit.pos);
                        @src_unit = null;
                    }
                }
            }
        }

        void add_menu_unit_order()
        {
            //-------------------------------------------------------------



            //-------------------------------------------------------------

            // 부대메뉴 : 해산
            if (部队指挥_解散_启用)
            {
                pk::menu_item 部队指挥_解散;
                部队指挥_解散.menu = unit_menu::菜单_部队;
                部队指挥_解散.init = pk::unit_menu_item_init_t(init);
                部队指挥_解散.get_text = pk::menu_item_get_text_t(getText_部队指挥_解散);
                部队指挥_解散.get_desc = pk::menu_item_get_desc_t(getDesc_部队指挥_解散);
                部队指挥_解散.is_visible = pk::menu_item_is_visible_t(isVisible);
                部队指挥_解散.is_enabled = pk::menu_item_is_enabled_t(isEnabled_部队指挥_解散);
                部队指挥_解散.get_targets = pk::unit_menu_item_get_targets_t(getTargets_部队指挥_解散);
                部队指挥_解散.get_chance = pk::unit_menu_item_get_chance_t(getChance_100);
                部队指挥_解散.handler = pk::unit_menu_item_handler_t(handler_部队指挥_解散);
                pk::add_menu_item(部队指挥_解散);
            }

            // 부대메뉴 : 병합
            if (部队指挥_合并_启用)
            {
                pk::menu_item 部队指挥_合并;
                部队指挥_合并.menu = unit_menu::菜单_部队;
                部队指挥_合并.init = pk::unit_menu_item_init_t(init);
                部队指挥_合并.get_text = pk::menu_item_get_text_t(getText_部队指挥_合并);
                部队指挥_合并.get_desc = pk::menu_item_get_desc_t(getDesc_部队指挥_合并);
                部队指挥_合并.is_visible = pk::menu_item_is_visible_t(isVisible);
                部队指挥_合并.is_enabled = pk::menu_item_is_enabled_t(isEnabled_部队指挥_合并);
                部队指挥_合并.get_targets = pk::unit_menu_item_get_targets_t(getTargets_部队指挥_合并);
                部队指挥_合并.get_chance = pk::unit_menu_item_get_chance_t(getChance_100);
                部队指挥_合并.handler = pk::unit_menu_item_handler_t(handler_部队指挥_合并);
                pk::add_menu_item(部队指挥_合并);
            }

            // 회복 : 소지금 启用하여 1부대 병력 회복
            if (部队指挥_招募乡勇_启用)
            {
                pk::menu_item 部队指挥_招募乡勇;
                部队指挥_招募乡勇.menu = unit_menu::菜单_部队;
                部队指挥_招募乡勇.init = pk::unit_menu_item_init_t(init);
                部队指挥_招募乡勇.get_text = pk::menu_item_get_text_t(getText_部队指挥_招募乡勇);
                部队指挥_招募乡勇.get_desc = pk::menu_item_get_desc_t(getDesc_部队指挥_招募乡勇);
                部队指挥_招募乡勇.is_visible = pk::menu_item_is_visible_t(isVisible);
                部队指挥_招募乡勇.is_enabled = pk::menu_item_is_enabled_t(isEnabled_部队指挥_招募乡勇);
                部队指挥_招募乡勇.get_targets = pk::unit_menu_item_get_targets_t(getTargets_部队指挥_招募乡勇);
                部队指挥_招募乡勇.get_chance = pk::unit_menu_item_get_chance_t(getChance_100);
                部队指挥_招募乡勇.handler = pk::unit_menu_item_handler_t(handler_部队指挥_招募乡勇);
                pk::add_menu_item(部队指挥_招募乡勇);
            }

            // 재편 : 부대 주장을 변경
            if (部队指挥_换帅_启用)
            {
                pk::menu_item 部队指挥_换帅;
                部队指挥_换帅.menu = unit_menu::菜单_部队;
                部队指挥_换帅.init = pk::unit_menu_item_init_t(init);
                部队指挥_换帅.get_text = pk::menu_item_get_text_t(getText_部队指挥_换帅);
                部队指挥_换帅.get_desc = pk::menu_item_get_desc_t(getDesc_部队指挥_换帅);
                部队指挥_换帅.is_visible = pk::menu_item_is_visible_t(isVisible);
                部队指挥_换帅.is_enabled = pk::menu_item_is_enabled_t(isEnabled_部队指挥_换帅);
                部队指挥_换帅.get_targets = pk::unit_menu_item_get_targets_t(getTargets_部队指挥_换帅);
                部队指挥_换帅.get_chance = pk::unit_menu_item_get_chance_t(getChance_100);
                部队指挥_换帅.handler = pk::unit_menu_item_handler_t(handler_部队指挥_换帅);
                pk::add_menu_item(部队指挥_换帅);
            }

            // 강행군 : 기력을 소비하여 추가 이동
            if (部队指挥_强行军_启用)
            {
                pk::menu_item 部队指挥_强行军;
                部队指挥_强行军.menu = unit_menu::菜单_部队;
                部队指挥_强行军.init = pk::unit_menu_item_init_t(init);
                部队指挥_强行军.get_text = pk::menu_item_get_text_t(getText_部队指挥_强行军);
                部队指挥_强行军.get_desc = pk::menu_item_get_desc_t(getDesc_部队指挥_强行军);
                部队指挥_强行军.is_visible = pk::menu_item_is_visible_t(isVisible);
                部队指挥_强行军.is_enabled = pk::menu_item_is_enabled_t(isEnabled_部队指挥_强行军);
                部队指挥_强行军.get_targets = pk::unit_menu_item_get_targets_t(getTargets_部队指挥_强行军);
                部队指挥_强行军.get_chance = pk::unit_menu_item_get_chance_t(getChance_100);
                部队指挥_强行军.handler = pk::unit_menu_item_handler_t(handler_部队指挥_强行军);
                pk::add_menu_item(部队指挥_强行军);
            }


        }

        //---------------------------------------------------------------------------



        void init(pk::unit@ unit, pk::point src_pos)
        {
            @src_unit = @unit;
            src_pos_ = src_pos;
        }

        int getChance_100(pk::point dst_pos)
        {
            return 100;
        }

        bool isVisible()
        {
            if (pk::is_campaign()) return false;
            if (!ch::get_set_p(0).get_mod_set(部队指挥扩展_开关)) return false;
            return true;
        }
        //---------------------------------------------------------------------------
        // 계략 설정 관련 함수
        //---------------------------------------------------------------------------


        int func_range_add()
        {
            if (!계략_특기_설정) return 0;

            if (ch::has_skill(src_unit, 特技_鬼谋))
                return 1;

            return 0;
        }

        //---------------------------------------------------------------------------

        bool handle_all(pk::point dst_pos, int action_id)
        {
            pk::action_info info();
            info.type = 8;
            info.action_id = action_id;
            info.target_pos = dst_pos;
            info.move_pos = src_unit.pos;
            ch::conduct_unit_action_8(src_unit, info);
            return true;
        }

        //---------------------------------------------------------------------------
        // 部队指挥_解散
        //---------------------------------------------------------------------------

        string getText_部队指挥_解散()
        {
            return pk::encode("解散");
        }

        string getDesc_部队指挥_解散()
        {
            if (src_unit.troops < 2000)
                return pk::encode("兵力需 2000 以上");
            else if (count_enemies_around(src_pos_) >= 1)
                return pk::encode("因为周围有敌军,所以无法执行");
            else
                return pk::encode("解散部队 (兵力全消失只回归将帅)");
        }

        bool isVisible_部队指挥_解散()
        {
            if (pk::is_campaign()) return false;
            return true;
        }

        bool isEnabled_部队指挥_解散()
        {
            if (src_unit.troops < 2000) return false;
            else if (count_enemies_around(src_pos_) >= 1) return false;
            return getTargets_部队指挥_解散().length > 0;
        }

        pk::array<pk::point_int> getTargets_部队指挥_解散()
        {
            pk::array<pk::point_int> target_units;

            if (count_enemies_around(src_pos_) < 1)
            {
                target_units.insertLast(pk::point_int(src_pos_, 1));
            }
            return target_units;
        }

        bool handler_部队指挥_解散(pk::point dst_pos)
        {
            //实际只能解散己方部队
            return handle_all(dst_pos, UNIT_COMMAND_DISBAND);
        }

        // 주위의 적부대, 적건물 수 검색
        int count_enemies_around(pk::point pos)
        {
            int count_enemy = 0;
            int max_range = 5;

            pk::array<pk::point> range = pk::range(pos, 1, max_range);
            for (int i = 0; i < int(range.length); i++)
            {
                pk::unit@ unit_around = pk::get_unit(range[i]);
                if (unit_around !is null and pk::is_enemy(src_unit, unit_around))
                    count_enemy += 1;

                pk::building@ building_around = pk::get_building(range[i]);
                if (building_around !is null and pk::is_enemy(src_unit, building_around))
                    count_enemy += 1;
            }

            return count_enemy;
        }

        bool check_spec_around(pk::unit@ unit)
        {
            int count_enemy = 0;
            int max_range = 2;

            pk::array<pk::point> range = pk::range(pk::get_unit_menu_hex_pos(), 1, max_range);
            for (int i = 0; i < int(range.length); i++)
            {
                pk::hex@ hex = pk::get_hex(range[i]);
                if (hex.has_building)
                {
                    auto building = pk::get_building(range[i]);
                    if (building.get_force_id() == unit.get_force_id())
                    {
                        if (ch::is_valid_spec_id(ch::to_spec_id(building.get_id())))
                            return true;
                    }
                }
            }

            return false;
        }

        //---------------------------------------------------------------------------
        // 部队指挥_合并 (삼국지13 오마쥬)
        //---------------------------------------------------------------------------

        string getText_部队指挥_合并()
        {
            return pk::encode("合并");
        }

        string getDesc_部队指挥_合并()
        {
            if (pk::get_person(src_unit.leader).rank >= 官职_无 and pk::get_person(src_unit.leader).mibun == 身份_一般)
                return pk::encode("官职不符合条件");
            else if (src_unit.troops < 2000)
                return pk::encode("兵力需 2000 以上");
            else if (count_enemies_around(src_pos_) >= 1)
                return pk::encode("因为周围有敌军,所以无法执行");
            else if (getTargets_部队指挥_合并().length == 0)
                return pk::encode("范围内没有同兵种我军部队");
            else
                return pk::encode("并入目标部队");
        }

        bool isVisible_部队指挥_合并()
        {
            if (pk::is_campaign()) return false;
            return true;
        }

        bool isEnabled_部队指挥_合并()
        {
            if (pk::get_person(src_unit.leader).rank >= 官职_无 and pk::get_person(src_unit.leader).mibun == 身份_一般) return false;
            else if (src_unit.troops < 2000) return false;
            else if (count_enemies_around(src_pos_) >= 1) return false;
            return getTargets_部队指挥_合并().length > 0;
        }

        pk::array<pk::point_int> getTargets_部队指挥_合并()
        {
            pk::array<pk::point_int> target_units;

            if (count_enemies_around(src_pos_) < 1)
            {
                auto range = pk::range(src_pos_, 1, 1);
                for (int i = 0; i < int(range.length); i++)
                {
                    auto dst_unit = pk::get_unit(range[i]);
                    if (dst_unit !is null and src_unit.pos != dst_unit.pos and src_unit.get_force_id() == dst_unit.get_force_id() and pk::get_ground_weapon_id(src_unit) == pk::get_ground_weapon_id(dst_unit))
                        target_units.insertLast(pk::point_int(range[i], 1));
                }
            }
            return target_units;
        }

        bool handler_部队指挥_合并(pk::point dst_pos)
        {
            return handle_all(dst_pos, UNIT_COMMAND_MERGE);
        }

        //---------------------------------------------------------------------------
        // 部队指挥_招募乡勇
        //---------------------------------------------------------------------------

        string getText_部队指挥_招募乡勇()
        {
            return pk::encode("招募乡勇");
        }

        string getDesc_部队指挥_招募乡勇()
        {
            if (pk::get_person(src_unit.leader).rank >= 官职_无 and pk::get_person(src_unit.leader).mibun == 身份_一般)
                return pk::encode("官职不符合条件");
            else if (src_unit.gold < GOLD_COST_招募乡勇)
                return pk::encode("金钱不足");
            else if (!check_spec_around(src_unit))
                return pk::encode("仅可在地名建筑周围2格执行");
            else
                return pk::encode("消耗金钱,招募乡勇参战");
        }

        bool isEnabled_部队指挥_招募乡勇()
        {
            if (pk::get_person(src_unit.leader).rank >= 官职_无 and pk::get_person(src_unit.leader).mibun == 身份_一般) return false;
            else if (src_unit.gold < GOLD_COST_招募乡勇) return false;
            else if (!check_spec_around(src_unit)) return false;
            return getTargets_部队指挥_招募乡勇().length > 0;
        }

        bool isVisible_部队指挥_招募乡勇()
        {
            if (pk::is_campaign()) return false;
            return true;
        }

        pk::array<pk::point_int> getTargets_部队指挥_招募乡勇()
        {
            pk::array<pk::point_int> target_units;
            target_units.insertLast(pk::point_int(src_pos_, 1));

            auto range = pk::range(src_pos_, 1, 2 + func_range_add());
            for (int i = 0; i < int(range.length); i++)
            {
                auto dst_unit = pk::get_unit(range[i]);
                if (dst_unit !is null and src_unit.pos != dst_unit.pos and src_unit.get_force_id() == dst_unit.get_force_id())
                    target_units.insertLast(pk::point_int(range[i], 1));
            }

            return target_units;
        }


        bool handler_部队指挥_招募乡勇(pk::point dst_pos)
        {
            return handle_all(dst_pos, UNIT_COMMAND_RECRUIT);
        }



        //---------------------------------------------------------------------------
        // 部队指挥_换帅
        //---------------------------------------------------------------------------

        string getText_部队指挥_换帅()
        {
            return pk::encode("换帅");
        }

        string getDesc_部队指挥_换帅()
        {
            if (src_unit.get_pos() != pk::get_unit_menu_hex_pos())
                return pk::encode("移动过后无法执行换帅.");
            else if (!pk::is_alive(pk::get_person(src_unit.member[1])))
                return pk::encode("没有副将");
            else if (count_enemies_around(src_pos_) >= 1)
                return pk::encode("因为周围有敌军,所以无法执行");
            return pk::encode("重新选择主将");
        }

        bool isVisible_部队指挥_换帅()
        {
            if (pk::is_campaign()) return false;
            if (src_unit.type != 部队类型_战斗) return false;
            return true;
        }

        bool isEnabled_部队指挥_换帅()
        {
            if (src_unit.get_pos() != pk::get_unit_menu_hex_pos()) return false;
            else if (!pk::is_alive(pk::get_person(src_unit.member[1]))) return false;
            else if (count_enemies_around(src_pos_) >= 1) return false;
            return getTargets_部队指挥_换帅().length > 0;
        }

        pk::array<pk::point_int> getTargets_部队指挥_换帅()
        {
            pk::array<pk::point_int> target_units;

            if (count_enemies_around(src_pos_) < 1)
            {
                target_units.insertLast(pk::point_int(src_pos_, 1));
            }
            return target_units;
        }

        bool handler_部队指挥_换帅(pk::point dst_pos)
        {
            return handle_all(dst_pos, UNIT_COMMAND_REPLACEMENT);
        }



        //---------------------------------------------------------------------------
        // 部队指挥_强行军 (삼국지7 오마쥬)
        //---------------------------------------------------------------------------

        string getText_部队指挥_强行军()
        {
            return pk::encode("强行军");
        }

        string getDesc_部队指挥_强行军()
        {
            if (pk::get_person(src_unit.leader).rank >= 官职_无 and pk::get_person(src_unit.leader).mibun == 身份_一般)
                return pk::encode("官职不符合条件");
            else if (src_unit.energy < ENERGY_MIN_강행군)
                return pk::encode("气力不足");
            else if (src_unit.type == 部队类型_运输) return pk::encode(pk::format("执行强行军 (必须 {} 气力，将损耗部分物资)", ENERGY_MIN_강행군));
            else
                return pk::encode(pk::format("执行强行军 (必须 {} 气力)", ENERGY_MIN_강행군));
        }

        bool isVisible_部队指挥_强行军()
        {
            if (pk::is_campaign()) return false;
            return true;
        }

        bool isEnabled_部队指挥_强行军()
        {
            if (pk::get_person(src_unit.leader).rank >= 官职_无 and pk::get_person(src_unit.leader).mibun == 身份_一般) return false;
            else if (src_unit.energy < ENERGY_MIN_강행군) return false;
            return getTargets_部队指挥_强行军().length > 0;
        }

        pk::array<pk::point_int> getTargets_部队指挥_强行军()
        {
            int movement = int(MOVEMENT_强行军 * src_unit.attr.stat[部队能力_移动]);

            // 이동 목표 지점 획득
            pk::array<pk::point_int> target_pos;
            auto range = pk::get_movable_pos(src_unit, src_pos_, movement); // 이동가능한 경로만 획득
            for (int i = 0; i < int(range.length); i++)
            {
                pk::hex@ hex = pk::get_hex(range[i]);
                target_pos.insertLast(pk::point_int(range[i], 1));
            }
            return target_pos;
        }

        bool handler_部队指挥_强行军(pk::point dst_pos)
        {
            return handle_all(dst_pos, UNIT_COMMAND_FORCED_MARCH);
        }


    }

    Main main;
}
